/* $Id: bitmap.c,v 1.4 2006-10-23 17:30:55 nicolasw Exp $ */

#include "bitmap.h"
#include <malloc.h>
#include <assert.h>
#include <stdio.h>

/* Bitmap para representar conjunto de enteros. Basado en un codigo C++ por 
 * Nicolas Wolovick. Escrito por Rafael Carrascosa para la catedra de Sistemas
 * Operativos, FaMAF, UNC.
 * Eres libre de modificar,utilizar y distribuir este codigo para cualquier 
 * fin siempre y cuando mantengas la autoria intacta.
 */

struct bitmap_s
{
	char *bmp;
	size_t capacity;
	size_t used;
};

#define INVREP(x) (x != NULL && x->bmp != NULL && x->capacity >= x->used)

bitmap_s *bitmap_create(size_t size)
{
	bitmap_s *bitmap = NULL;
	if(size == 0) return NULL;
	bitmap = malloc(sizeof (struct bitmap_s));
	if(bitmap == NULL) return NULL;
	/* Ajustar size para que sea multiplo de 8 (bits) */
	if(size % 8 != 0) size += 8 - (size % 8);
	bitmap->bmp = malloc (sizeof(char) * (size/8));
	bitmap->capacity = size;
	bitmap->used = 0;
	return bitmap;
}

void bitmap_destroy(bitmap_s *bitmap)
{
	assert(INVREP(bitmap));
	free(bitmap->bmp);
	free(bitmap);
}

bool bitmap_member(const bitmap_s *bitmap,size_t location)
{
	size_t pos=0,bit = 0;
	char mask=0;
	assert(INVREP(bitmap) && location < bitmap->capacity);
	pos = location / 8;
	bit = location % 8;
	mask = 1<<(bit); /* Pej si bit==5 entonces mask == `00010000` */
	mask = bitmap->bmp[pos] & mask; /* AND bit a bit */
	/* Notar que si el pos-esimo bit de mask sigue siendo 1 entonces
	   mask != 0 */
	return (mask != 0);
}

void bitmap_insert(bitmap_s *bitmap,size_t location)
{
	size_t pos=0,bit = 0;
	char mask=0;
	assert(INVREP(bitmap) && location < bitmap->capacity);
	bitmap->used++;
	pos = location / 8;
	bit = location % 8;
	mask = 1<<(bit); /* Pej si bit==5 entonces mask == `00010000` */
	bitmap->bmp[pos] = bitmap->bmp[pos] | mask; /* OR bit a bit */
	/* Notar que el unico bit modificado es el pos-esimo porque el 0
	 es neutro para OR y el 1 es absorbente */
}

void bitmap_remove(bitmap_s *bitmap,size_t location)
{
	size_t pos=0,bit = 0;
	char mask=0;
	assert(INVREP(bitmap) && location < bitmap->capacity);
	bitmap->used--;
	pos = location / 8;
	bit = location % 8;
	mask = 1<<(bit); /* Pej si bit==5 entonces mask == `00010000` */
	mask = ~mask; /* Negacion bit a bit */
	bitmap->bmp[pos] = bitmap->bmp[pos] & mask; /* AND bit a bit */
	/* Notar que el unico bit modificado es el pos-esimo porque el 0
	 es absorvente para AND y el 1 es neutro */
}

size_t bitmap_size(const bitmap_s *bitmap)
{
	assert(INVREP(bitmap));
	return bitmap->used;
}

size_t bitmap_capacity(const bitmap_s *bitmap)
{
// 	printf("esto es lo que vale x->capacity: %i y >= x->used %i", bitmap->capacity, bitmap-> used);
	assert(INVREP(bitmap));
	return bitmap->capacity;
}

bool bitmap_empty(const bitmap_s *bitmap)
{
	assert(INVREP(bitmap));
	return bitmap->used == 0;
}
